
                    
                    MEMBER

 INCLUDE('Errors.clw'),ONCE
 INCLUDE('AnyAscii.inc'),ONCE

AnyAsciiFileName        CSTRING(FILE:MaxFilePath+FILE:MaxFileName+1),STATIC
AnyAsciiFile            FILE,DRIVER('ASCII'),CREATE,NAME(AnyAsciiFileName),PRE(AsciiFile)
                          RECORD
TextLine                    STRING(ANYASCII_IO_SIZE)
                          END
                        END

! First off link the appropriate ASCII file driver that will be required to link successfully...

 COMPILE('DLL ?',Dll_Mode)          ! First we need a Dll_Mode negated symbol
_ABCLibMode_ EQUATE(False)          ! for the LINK attributes that follow below
 DLL ?
 OMIT('LIB ?',Dll_Mode)
_ABCLibMode_ EQUATE(True)
 LIB ?

  
!-----------------------------------------------------------------------------------------
!CreateFile
! Initialize the class by creating a new (or truncating an existing) file to operate on
!-----------------------------------------------------------------------------------------
AnyAsciiFileClass.CreateFile        PROCEDURE(STRING AsciiFileName, LONG OpenMode=ReadWrite+DenyWrite)
 CODE

 RETURN SELF.InitFile(AsciiFileName, True, OpenMode)


!-----------------------------------------------------------------------------------------
!OpenFile
! Initialize the class by opening an existing file to operate on
!-----------------------------------------------------------------------------------------
AnyAsciiFileClass.OpenFile          PROCEDURE(STRING AsciiFileName, LONG OpenMode=ReadWrite+DenyWrite)
 CODE

 RETURN SELF.InitFile(AsciiFileName, False, OpenMode)


!-----------------------------------------------------------------------------------------
!OpenOrCreateFile
! Initialize the class by opening an existing file or alternatively creating a new file 
! when the file does not exist
!-----------------------------------------------------------------------------------------
AnyAsciiFileClass.OpenOrCreateFile  PROCEDURE(STRING AsciiFileName, LONG OpenMode=ReadWrite+DenyWrite)
 CODE

 IF EXISTS(AsciiFileName)
    RETURN SELF.InitFile(AsciiFileName, False, OpenMode)
 ELSE
    RETURN SELF.InitFile(AsciiFileName, True, OpenMode)
 END


!-----------------------------------------------------------------------------------------
!GetName
! Returns the current file name of the file being operated on
!-----------------------------------------------------------------------------------------
AnyAsciiFileClass.GetName           PROCEDURE()
 CODE

 RETURN SELF.FileName


!-----------------------------------------------------------------------------------------
!Read
! Reads a line of text into the string buffer specified by TextLine
! If no specific text file position is specified then the next file line in sequence 
! is retrieved.
!-----------------------------------------------------------------------------------------
AnyAsciiFileClass.Read              PROCEDURE(*CSTRING TextLine, <ULONG ReadPosition>)
NullPtrCheck                        &CSTRING
 CODE

 IF ~SELF.FileName THEN RETURN LEVEL:Fatal.
 NullPtrCheck &= TextLine
 IF  NullPtrCheck &= NULL THEN RETURN LEVEL:Fatal.

 SELF.InitFile()

 IF ~OMITTED(3) 
    GET(AnyAsciiFile, ReadPosition)
 ELSE
    GET(AnyAsciiFile, SELF.ReadPosition)
 END
 IF ERRORCODE() THEN RETURN LEVEL:Notify.
 
 SELF.PreviousReadPosition = POINTER(AnyAsciiFile)
 SELF.ReadPosition = POINTER(AnyAsciiFile) + BYTES(AnyAsciiFile)

 TextLine = SUB(AnyAsciiFile:TextLine, 1, LEN(CLIP(AnyAsciiFile:TextLine)))

 RETURN LEVEL:Benign


AnyAsciiFileClass.Read              PROCEDURE(*STRING TextLine, <ULONG ReadPosition>)
NullPtrCheck                        &STRING
cTextLine                           CSTRING(ANYASCII_IO_SIZE+1),AUTO
ReturnValue                         BYTE,AUTO
 CODE

 IF ~SELF.FileName THEN RETURN LEVEL:Fatal.
 NullPtrCheck &= TextLine
 IF  NullPtrCheck &= NULL THEN RETURN LEVEL:Fatal.

 IF OMITTED(3) 
    ReturnValue = SELF.Read(cTextLine)
 ELSE
    ReturnValue = SELF.Read(cTextLine, ReadPosition)
 END

 TextLine = cTextLine

 RETURN ReturnValue


AnyAsciiFileClass.Read              PROCEDURE(*PSTRING TextLine, <ULONG ReadPosition>)
NullPtrCheck                        &PSTRING
cTextLine                           CSTRING(ANYASCII_IO_SIZE+1),AUTO
ReturnValue                         BYTE,AUTO
 CODE

 IF ~SELF.FileName THEN RETURN LEVEL:Fatal.
 NullPtrCheck &= TextLine
 IF  NullPtrCheck &= NULL THEN RETURN LEVEL:Fatal.

 IF OMITTED(3) 
    ReturnValue = SELF.Read(cTextLine)
 ELSE
    ReturnValue = SELF.Read(cTextLine, ReadPosition)
 END

 TextLine = cTextLine

 RETURN ReturnValue


!-----------------------------------------------------------------------------------------
!Replace
! Replaces the previously read line of text with the text specified by TextLine
!-----------------------------------------------------------------------------------------
AnyAsciiFileClass.Replace           PROCEDURE(STRING TextLine)
ReturnValue                         BYTE(LEVEL:Benign)
 CODE

 IF ~SELF.FileName THEN RETURN LEVEL:Fatal.
 IF ~SELF.PreviousReadPosition THEN RETURN LEVEL:Notify.

 SELF.InitFile()

 GET(AnyAsciiFile, SELF.PreviousReadPosition)

 IF LEN(CLIP(TextLine)) >= LEN(CLIP(AnyAsciiFile:TextLine))
    AnyAsciiFile:TextLine = SUB(TextLine, 1, LEN(CLIP(AnyAsciiFile:TextLine)))
 ELSE
    AnyAsciiFile:TextLine = SUB(TextLine & ALL(' ', ANYASCII_IO_SIZE), 1, |
                            LEN(CLIP(AnyAsciiFile:TextLine))-1) & CHR(0)
 END
 PUT(AnyAsciiFile)
 IF ERRORCODE() 
    ReturnValue = LEVEL:Notify
 END

 IF SELF.AutoFlush THEN CLOSE(AnyAsciiFile).

 RETURN ReturnValue


!-----------------------------------------------------------------------------------------
!Write
! Writes a line of text specified by TextLine to the end of the file
!-----------------------------------------------------------------------------------------
AnyAsciiFileClass.Write             PROCEDURE(STRING TextLine)
ReturnValue                         BYTE(LEVEL:Benign)
 CODE

 IF ~SELF.FileName THEN RETURN LEVEL:Fatal.

 SELF.InitFile()

 AnyAsciiFile:TextLine = CLIP(TextLine)
 ADD(AnyAsciiFile)
 IF ERRORCODE() 
    !ASSERT(False, ERROR())
    ReturnValue = LEVEL:Notify
 END

 IF SELF.AutoFlush THEN CLOSE(AnyAsciiFile).

 RETURN ReturnValue


!-----------------------------------------------------------------------------------------
!IsOpen
! Returns a boolean indication of whether or not the file is open
!-----------------------------------------------------------------------------------------
AnyAsciiFileClass.IsOpen            PROCEDURE()
 CODE

 IF ~SELF.FileName 
    RETURN False
 ELSE
    RETURN True
 END


!-----------------------------------------------------------------------------------------
!GetReadPosition
! Returns the current text file position in the read sequence
! (This is the position that will be read from by the read functions when no position
! is explicitly specified)
!-----------------------------------------------------------------------------------------
AnyAsciiFileClass.GetReadPosition   PROCEDURE()
 CODE

 IF ~SELF.FileName 
    RETURN False
 ELSE
    RETURN SELF.ReadPosition
 END


!-----------------------------------------------------------------------------------------
!SetReadPosition
! Sets/Resets the current text file position in the read sequence
! (Sets the position that will be read from by the read functions when no position
! is explicitly specified)
!-----------------------------------------------------------------------------------------
AnyAsciiFileClass.SetReadPosition   PROCEDURE(ULONG ReadPosition)
 CODE

 IF ~SELF.FileName 
    RETURN
 ELSE
    SELF.ReadPosition = ReadPosition
 END


!-----------------------------------------------------------------------------------------
!GetWritePosition
! Returns the current text file position in the write sequence
! (This is the position that will be written to by the write functions, i.e. the number of
! bytes in the file + 1)
!-----------------------------------------------------------------------------------------
AnyAsciiFileClass.GetWritePosition  PROCEDURE()
WritePosition                       ULONG(1)
 CODE

 IF ~SELF.FileName THEN RETURN False.

 SELF.InitFile()

 SET(AnyAsciiFile)
 LOOP 
    NEXT(AnyAsciiFile)
    IF ERRORCODE() THEN BREAK.
    WritePosition = POINTER(AnyAsciiFile) + BYTES(AnyAsciiFile)
 END

 RETURN WritePosition


!-----------------------------------------------------------------------------------------
!CloseFile
! Closes the file being operated on
!-----------------------------------------------------------------------------------------
AnyAsciiFileClass.CloseFile         PROCEDURE()
 CODE

 IF ~SELF.FileName THEN RETURN.

 CLOSE(AnyAsciiFile)

 CLEAR(SELF.Filename)


!-----------------------------------------------------------------------------------------
!SetAutoFlush
! Sets "Auto Flush" behaviour. When "Auto Flush" is enabled the file is closed after each 
! disk write to force "flushing" the file. While this behaviour causes slower file I/O it
! may be desirable for logging and situates where a partially written file because of a 
! program crash is desirable, etc.
!-----------------------------------------------------------------------------------------
AnyAsciiFileClass.SetAutoFlush      PROCEDURE(BYTE AutoFlush)
 CODE

 SELF.AutoFlush = AutoFlush


!-----------------------------------------------------------------------------------------
!InitFile
! For internal use only, by CreateFile & OpenFile
!-----------------------------------------------------------------------------------------
AnyAsciiFileClass.InitFile          PROCEDURE(<STRING AsciiFileName>, BYTE CreateFile=False, LONG OpenMode=ReadWrite+DenyWrite)
 CODE

 IF OMITTED(2)
    IF STATUS(AnyAsciiFile) = SELF.OpenMode AND NAME(AnyAsciiFile) = SELF.FileName 
       RETURN LEVEL:Benign
    END
    AnyAsciiFileName = SELF.FileName
    OpenMode = SELF.OpenMode
 ELSE
    AnyAsciiFileName = CLIP(AsciiFileName)
 END

 IF STATUS(AnyAsciiFile) THEN CLOSE(AnyAsciiFile).

 IF CreateFile
    LOOP 50 TIMES
       REMOVE(AnyAsciiFileName)
       REMOVE(AnyAsciiFile)
       CREATE(AnyAsciiFile)
    WHILE ERRORCODE()
    IF ERRORCODE() THEN RETURN LEVEL:Notify.
 END

 LOOP 50 TIMES
    OPEN(AnyAsciiFile, OpenMode)
 WHILE ERRORCODE()
 IF ERRORCODE() 
    !ASSERT(False, ERROR())
    RETURN LEVEL:Notify
 END

 IF ~OMITTED(2) 
    SELF.FileName      = NAME(AnyAsciiFile)
    SELF.OpenMode      = STATUS(AnyAsciiFile)
    SELF.ReadPosition  = 1
 END

 RETURN LEVEL:Benign


!-----------------------------------------------------------------------------------------
!Destruct
! Automatic destructor to ensure the file is closed properly 
!-----------------------------------------------------------------------------------------
AnyAsciiFileClass.Destruct          PROCEDURE
 CODE

 SELF.CloseFile()


